package com.smsc.headend.task.engine.service.push.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.smsc.headend.common.constant.DeviceModel;
import com.smsc.headend.common.enums.DeviceType;
import com.smsc.headend.common.utils.CosemUtils;
import com.smsc.headend.common.utils.CustomStringUtils;
import com.smsc.headend.common.utils.ProtoBufferUtil;
import com.smsc.headend.module.asset.dmo.MeterConfigDMO;
import com.smsc.headend.module.asset.entity.Meter;
import com.smsc.headend.module.data.dmo.GroupSubDataItem;
import com.smsc.headend.module.data.enums.OperationGroup;
import com.smsc.headend.module.data.enums.OperationName;
import com.smsc.headend.module.event.dto.DeviceNotificationDto;
import com.smsc.headend.module.event.entity.*;
import com.smsc.headend.module.protocol.cosem.bo.CosemData;
import com.smsc.headend.module.protocol.cosem.util.ByteNumberUtils;
import com.smsc.headend.module.protocol.cosem.util.ByteUtils;
import com.smsc.headend.module.push.entity.ConfigNotifyType;
import com.smsc.headend.module.push.entity.ConfigNotifyTypeParam;
import com.smsc.headend.module.task.consts.TaskKafkaTopic;
import com.smsc.headend.module.task.dto.*;
import com.smsc.headend.module.task.enums.TaskType;
import com.smsc.headend.module.task.proto.TaskEventDataProto;
import com.smsc.headend.module.template.alarmfilter.entity.AlarmObjEntity;
import com.smsc.headend.module.template.alarmfilter.entity.AlarmTypeEntity;
import com.smsc.headend.task.engine.mapper.AlarmObjMapper;
import com.smsc.headend.task.engine.mapper.AlarmTypeMapper;
import com.smsc.headend.task.engine.mapper.DeviceRelationMapper;
import com.smsc.headend.task.engine.mapper.RdAlarmMeterMapper;
import com.smsc.headend.task.engine.po.DeviceDetail;
import com.smsc.headend.task.engine.service.CosemXmlService;
import com.smsc.headend.task.engine.service.FeignAssetManagementService;
import com.smsc.headend.task.engine.service.asset.AssetService;
import com.smsc.headend.task.engine.service.push.ConfigNotifyTypeParamService;
import com.smsc.headend.task.engine.service.push.PushDataDecodeHandler;
import com.smsc.headend.task.engine.service.task.TaskService;
import lombok.extern.slf4j.Slf4j;
import org.assertj.core.util.Lists;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.kafka.core.KafkaTemplate;

import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.stream.Collectors;


/**
 * (业务实现)
 *
 * @author wjh
 * @date 2022/6/17 9:18.
 */
@Slf4j
public class EventAndAlarmHandlerImpl implements PushDataDecodeHandler {

    Set<Integer> needAsciiDecodeEventTypes = Collections.unmodifiableSet(new HashSet<Integer>() {{
        add(110001103);//Meter Clock Diff Over Limit
        add(110001106);//Meter Read Fail
    }});

    @Autowired
    ConfigNotifyTypeParamService paramService;
    @Autowired
    CosemXmlService cosemXmlService;
    @Autowired
    FeignAssetManagementService assetManagementService;
    @Autowired
    KafkaTemplate kafkaTemplate;
    @Autowired
    AssetService assetService;
    @Autowired
    TaskService taskService;
    @Autowired
    AlarmObjMapper alarmObjMapper;
    @Autowired
    AlarmTypeMapper alarmTypeMapper;
    @Autowired
    RdAlarmMeterMapper rdAlarmMeterMapper;
    @Autowired
    DeviceRelationMapper deviceRelationMapper;

    private final static Set<Integer> BRAZIL_POC_METER_MODEL_SET = new HashSet() {
        {
            add(DeviceModel.Ameter100_BR_1P2);
            add(DeviceModel.Ameter100_BR_2P3);
            add(DeviceModel.Ameter300_BR_DC);
            add(DeviceModel.Ameter300_BR_CT);
//            add(DeviceModel.WFCT_960);
        }
    };

    @Override
    public void handler(CosemData cosemData, ConfigNotifyType configNotifyType, DeviceDetail deviceDetail, Long dataItemId, Date uploadDate) {
        long modelId = deviceDetail.getDeviceTypeGroup().getModelId();
        long deviceType = deviceDetail.getDeviceTypeGroup().getDeviceType();
        long deviceId = deviceDetail.getDeviceId();
        uploadDate = null == uploadDate ? new Date() : uploadDate;
        List<ConfigNotifyTypeParam> params = paramService.getListByNotifyTypeId(configNotifyType.getNotifyTypeId());
        Map<String, ConfigNotifyTypeParam> paramMap = params
                .stream()
                .collect(Collectors.toMap(ConfigNotifyTypeParam::getParamName, e -> e));
        ConfigNotifyTypeParam eventCodeParam = paramMap.get("eventCode");
        ConfigNotifyTypeParam childDataParam = paramMap.get("childData");
        ConfigNotifyTypeParam childUploadDateParam = paramMap.get("childUploadDate");
        if (null == childDataParam) {
            log.error("decode alarm/event error,no param:childDataParam");
            return;
        }
        Integer eventCode = null;
        List<CosemData> childData = new ArrayList<>();
        if (StrUtil.isEmpty(childDataParam.getParamIndex())) {
            //没有配置index则取本身
            childData.add(cosemData);
        } else {
            CosemData cosemDataParent = paramService.getCosemDataByIndex(cosemData, childDataParam.getParamIndex());
            if (null == cosemDataParent) {
                log.error("decode alarm/event error,cosemDataParent is null");
            }
            if (cosemDataParent.getType().equals("Array")) {
                childData = cosemDataParent.getChild();
            } else {
                childData.add(cosemDataParent);
            }
        }
        //如果配置了eventCode的解析方式，则用配置解析
        if (null != eventCodeParam) {
            for (CosemData child : childData) {
                if (null != childUploadDateParam) {
                    CosemData childUploadDate = paramService.getCosemDataByIndex(child, childUploadDateParam.getParamIndex());
                    uploadDate = (Date) cosemXmlService.getData("DateTime", childUploadDate.getValue());
                }
                CosemData eventCodeData = paramService.getCosemDataByIndex(child, eventCodeParam.getParamIndex());
                if (null != eventCodeData) {
                    eventCode = Convert.toInt(cosemXmlService.getData(eventCodeData.getType(), eventCodeData.getValue()));
                    Integer eventType = assetManagementService.getModelEventType(modelId, eventCode, dataItemId, deviceType);
                    if (eventType == null) {
                        log.error("fail to get model {} eventType by {}", modelId, eventCode);
                        continue;
                    }
                    DeviceNotificationDto notificationItemList = null;
                    try {
                        notificationItemList = assetManagementService.getDeviceNotificationItem(modelId, dataItemId);
                    } catch (Exception e) {
                        log.error("Exception {}", e);
                    }
                    if (null != notificationItemList) {
                        //解析子数据项需要
                        dataItemId = null;
                    }
                    savePushUpEventData(eventCode, eventType, child, uploadDate, notificationItemList, deviceId, deviceType, dataItemId);
                } else {
                    log.error("decode alarm/event error,can not get eventCode by paramIndex:{}", eventCodeParam.getParamIndex());
                    continue;
                }
            }
            return;
        }
        //没有配置了eventCode的解析方式，则用ConfigDeviceDataNotify来解析报文
        DeviceNotificationDto notificationItemList = assetManagementService.getDeviceNotificationItem(modelId, null);
        Date finalUploadDate = uploadDate;
        Long finalDataItemId = dataItemId;
        childData.stream().forEach(notification -> processEventAndAlarm(modelId, deviceType, deviceId, finalDataItemId, finalUploadDate, notification, notificationItemList));
    }

    private void processEventAndAlarm(Long modelId, Long deviceType, Long deviceId, Long dataItemId, Date uploadDate, CosemData notificationDataValue, DeviceNotificationDto notificationItemList) {
        Integer eventCode = getEventCode(notificationItemList, notificationDataValue, dataItemId);
        //推送报文中包含EventCode和数据项
        if (eventCode != null) {
            Integer eventType = assetManagementService.getModelEventType(modelId, eventCode, dataItemId, deviceType);
            if (eventType == null) {
                log.error("fail to get model {} eventType by {}", modelId, eventCode);
                return;
            }
            savePushUpEventData(eventCode, eventType, notificationDataValue, uploadDate, notificationItemList, deviceId, deviceType, dataItemId);
        } else {
            // Alarm Describer
            Map<String, Long[]> lbDataItems = MapUtil.newHashMap();
            if (null == notificationItemList) {
                log.warn("notificationItemList is null");
                return;
            }
            for (GroupSubDataItem groupSubDataItem : notificationItemList.getObjectList()) {
                CosemData data = notificationDataValue.getChildAt(0).getChildAt(Convert.toInt(groupSubDataItem.getIndex()) - 1);
                Object value = cosemXmlService.getData(data.getType(), data.getValue());
                String str = Long.toHexString(Convert.toLong(value)); // 获取的Uint32转成了String
                str = CustomStringUtils.getNumberStringWithCount(str, 8); // 转成8位二进制
                str = CustomStringUtils.hexStringToBitString(str); //转成32位0或者1的二进制;
                if (!str.contains("1")) {
                    continue;
                }
                String taskNo = null;
                //处理Alarm Descriptor
                if (BRAZIL_POC_METER_MODEL_SET.contains(modelId.intValue()) && 1020010021102L == (groupSubDataItem.getSubDataItemId()) && ("1".equals(Convert.toStr(value)) || "2".equals(Convert.toStr(value)))) {
                    //巴西WI-SUN电表上报AD时，掉电（00000001）和上电（00000002）事件不需要清除
                } else {
                    taskNo = clearAdAndAr(deviceId, groupSubDataItem.getSubDataItemId(), str);
                }
                str = StrUtil.reverse(str);
                AlarmObjEntity alarmObj = alarmObjMapper.selectOne(Wrappers.<AlarmObjEntity>lambdaQuery().eq(AlarmObjEntity::getSubDataItemId, groupSubDataItem.getSubDataItemId()));
                List<AlarmTypeEntity> alarmTypes = alarmTypeMapper.selectList(Wrappers.<AlarmTypeEntity>lambdaQuery().eq(AlarmTypeEntity::getAlarmTypeId, alarmObj.getAlarmObjId()).orderByAsc(AlarmTypeEntity::getAlarmBit));
                if (CollUtil.isEmpty(alarmTypes)) {
                    log.error("Device Event: no alarmTypes, deviceType={},deviceId={},modelId={}", deviceType, deviceId, modelId);
                    continue;
                }
                List<String> matchedAlarms = CollUtil.newArrayList();
                for (int i = 0; i < str.toCharArray().length; i++) {
                    if (str.toCharArray()[i] == '1') {
                        AlarmTypeEntity alarmType = alarmTypes.get(i);
                        if (alarmType == null) {
                            continue;
                        }
                        matchedAlarms.add(alarmType.getAlarmTypeDesc());
                        // alarm 入库
                        String alarmLogSeq = saveRdAlarmMeter(deviceId, alarmType.getAlarmTypeId(), alarmType.getAlarmBit(), uploadDate, taskNo);
                        if (StrUtil.isNotEmpty(alarmType.getLbDataItemIds())) {
                            String[] ids = alarmType.getLbDataItemIds().split(",");
                            lbDataItems.put(alarmLogSeq, Arrays.stream(ids).map(id -> Convert.toLong(id)).toArray(size -> new Long[size]));
                        }
                    }
                }
                if (CollUtil.isNotEmpty(matchedAlarms)) {
                    Meter meter = assetService.getMeterById(deviceId);
                    Map<String, Object> map = MapUtil.newHashMap();
                    map.put("customerSn", meter.getCustomerSn());
                    map.put("tv", uploadDate.getTime());
                    map.put("alarms", CollUtil.join(matchedAlarms, ","));
                    kafkaTemplate.send(TaskKafkaTopic.ALARM_TO_ADAPTER_FOR_EMAIL, JSONUtil.toJsonStr(map).getBytes(StandardCharsets.UTF_8));
                }
            }
            if (CollUtil.isNotEmpty(lbDataItems)) {
                PullEventData data = new PullEventData();
                data.setDeviceId(deviceId);
                data.setDeviceType(deviceType);
                data.setLbDataItems(lbDataItems);
                kafkaTemplate.send(TaskKafkaTopic.PULL_EVENT_TASK, JSONUtil.toJsonStr(data).getBytes(StandardCharsets.UTF_8));
            }
        }
    }

    private String clearAdAndAr(Long meterId, Long subDataItemId, String value) {
        String alarmFilterValue = CustomStringUtils.bitStringToHexString(value); //二进制转成十六进制
        Long alarmLongValue = Long.parseLong(alarmFilterValue, 16);
        MeterConfigDMO meterConfigDMO = assetManagementService.getMeterConfigById(meterId);

        Task task = new Task();
        task.setComId(meterConfigDMO.getComId());
        task.setMeterId(meterId);
        task.setTaskType(TaskType.AlarmDescriptor.toString());
        task.setIsODR(true);
        task.setMessageId(UUID.randomUUID().toString());
        task.setPriority(Task.Priority.NORMAL.getPriorityCode());
        String taskNo = UUID.randomUUID().toString();
        task.setTaskNo(taskNo);

        List<SubTaskGroup> subTaskGroups = CollUtil.newArrayList();
        SubTaskGroup subTaskGroup = new SubTaskGroup();
        subTaskGroup.setGroupId(OperationGroup.GeneralParametersSet.getId().longValue());
        List<AtomicTask> atomicTasks = new ArrayList<>();

        AtomicTask adAtomicTask = new AtomicTask();
        adAtomicTask.setSeq(0);
        adAtomicTask.setGroupId(subTaskGroup.getGroupId());
        adAtomicTask.setAtomicTaskNo(UUID.randomUUID().toString());
        adAtomicTask.setTaskNo(taskNo);
        adAtomicTask.setOperationId(OperationName.GeneralParamSet.getId().longValue());
        Map<String, Object> atomicTaskParam = MapUtil.newHashMap();
        atomicTaskParam.put("subDataItemId", subDataItemId);
        atomicTaskParam.put("value", alarmLongValue);
        adAtomicTask.setAtomicTaskParam(JSONUtil.toJsonStr(atomicTaskParam));
        atomicTasks.add(adAtomicTask);

        // 先不清除AR
        /*AtomicTask arAtomicTask = new AtomicTask();
        arAtomicTask.setSeq(1);
        arAtomicTask.setGroupId(subTaskGroup.getGroupId());
        arAtomicTask.setAtomicTaskNo(UUID.randomUUID().toString());
        arAtomicTask.setTaskNo(taskNo);
        arAtomicTask.setOperationId(OperationName.GeneralParamSet.getId().longValue());
        Map<String, Object> atomicTaskParam1 = MapUtil.newHashMap();
        atomicTaskParam1.put("subDataItemId", adMapAr.get(subDataItemId));
        atomicTaskParam1.put("value", alarmLongValue);
        arAtomicTask.setAtomicTaskParam(JSONUtil.toJsonStr(atomicTaskParam1));
        atomicTasks.add(arAtomicTask);*/

        subTaskGroup.setSubTasks(atomicTasks);
        subTaskGroups.add(subTaskGroup);
        task.setSubTaskGroups(subTaskGroups);
        log.info("clear ad and ar task: {}", JSONUtil.toJsonStr(task));
        taskService.sendTaskToGenerator(task);
        return taskNo;
    }

    private String saveRdAlarmMeter(Long meterId, Integer alarmObjId, Integer alarmBit, Date uploadDate, String taskNo) {
        RdAlarmMeter rdAlarmMeter = new RdAlarmMeter();
        String logSeq = UUID.randomUUID().toString();
        rdAlarmMeter.setLogSeq(logSeq);
        rdAlarmMeter.setMeterId(meterId);
        rdAlarmMeter.setAlarmObjId(alarmObjId);
        rdAlarmMeter.setAlarmBit(alarmBit);
        rdAlarmMeter.setTaskNo(taskNo);
        if (uploadDate != null) {
            rdAlarmMeter.setTvAlarm(uploadDate.getTime() / 1000);
        }
        int rtn = rdAlarmMeterMapper.insert(rdAlarmMeter);
        if (rtn >= 1) {
            return logSeq;
        }
        return null;
    }

    private Integer getEventCode(DeviceNotificationDto notificationItemList, CosemData notificationDataValue, Long dataItemId) {
        if (notificationItemList == null) {
            return null;
        }
        Integer i = 0;
        Boolean hasEventCode = false;
        for (GroupSubDataItem groupSubDataItem : notificationItemList.getObjectList()) {
            if (groupSubDataItem.getDataGroupIds().contains(GroupSubDataItem.SpecialDataGroup.EVENT_CODE.getCode())) {
                hasEventCode = true;
                break;
            }
            i++;
        }
        if (!hasEventCode) {
            return null;
        }
        CosemData cosemData;
        if (dataItemId == null) {
            cosemData = notificationDataValue.getChildAt(0).getChildAt(i);
        } else {
            cosemData = notificationDataValue.getChildAt(i);
        }
        return Convert.toInt(cosemXmlService.getData(cosemData.getType(), cosemData.getValue()));
    }

    private TaskEventData savePushUpEventData(Integer eventCode, Integer type, CosemData notificationDataValue, Date uploadDate, DeviceNotificationDto notificationItemList, Long deviceId, Long deviceType, Long dataItemId) {
        if (deviceType == DeviceType.METER.getId().longValue() || deviceType == DeviceType.GPRS.getId().longValue()) {
            RdEventMeter rdEventMeter = new RdEventMeter();
            rdEventMeter.setLogSeq(UUID.randomUUID().toString());
            rdEventMeter.setEventType(type);
            rdEventMeter.setMeterId(deviceId);
            rdEventMeter.setEventCode(eventCode);
            rdEventMeter.setTv(getEventTv(uploadDate, notificationDataValue, notificationItemList, dataItemId));
            rdEventMeter.setTvUpdate(System.currentTimeMillis() / 1000);
            //推送固定使用data_item_id
            rdEventMeter.setLbDataItemId(1024000001l);
            rdEventMeter.setReceiveType(1);
            // rdEventMeterMapper.insert(rdEventMeter);
            if (dataItemId == null) {
                List<RdEventMeterData> subData = saveEventSubData(rdEventMeter.getLogSeq(), notificationDataValue, notificationItemList);
                rdEventMeter.setSubData(subData);
            }
            meterEventSendToDDS(rdEventMeter);
        } else if (deviceType == DeviceType.DCU.getId().longValue()) {
            RdEventDcu rdEventDcu = new RdEventDcu();
            rdEventDcu.setLogSeq(UUID.randomUUID().toString());
            rdEventDcu.setEventType(type.longValue());
            rdEventDcu.setEventCode(eventCode);
            rdEventDcu.setDcuId(deviceId);
            if (dataItemId == null) {
                rdEventDcu.setTv(uploadDate.getTime() / 1000);
            } else {
                rdEventDcu.setTv(getEventTv(uploadDate, notificationDataValue, notificationItemList, dataItemId));
            }
            rdEventDcu.setTvUpdate(System.currentTimeMillis() / 1000);
            rdEventDcu.setReceiveType(1);
            // rdEventDcuMapper.insert(rdEventDcu);
            if (dataItemId == null) {
                List<RdEventDcuData> subData = saveDcuEventSubData(rdEventDcu.getLogSeq(), type, notificationDataValue, notificationItemList);
                rdEventDcu.setSubData(subData);
            }
            meterEventSendToDDS(rdEventDcu);
        } else {
            log.error("deviceType not support {}", deviceType);
        }
        return null;
    }

    private void meterEventSendToDDS(AbstractRdEvent rdEvent) {
        TaskEventData taskEventData = new TaskEventData();
        if (rdEvent instanceof RdEventMeter) {
            RdEventMeter rdEventMeter = (RdEventMeter) rdEvent;
            taskEventData.setRdEventMeter(Lists.newArrayList(rdEventMeter));
            taskEventData.setDeviceId(rdEventMeter.getMeterId());
            taskEventData.setDeviceType(DeviceType.METER.getId());
            taskEventData.setIsODR(false);
        } else if (rdEvent instanceof RdEventDcu) {
            RdEventDcu rdEventDcu = (RdEventDcu) rdEvent;
            taskEventData.setRdEventDcu(Lists.newArrayList(rdEventDcu));
            taskEventData.setDeviceId(rdEventDcu.getDcuId());
            taskEventData.setDeviceType(DeviceType.DCU.getId());
            taskEventData.setIsODR(false);
        }
        kafkaTemplate.send(TaskKafkaTopic.DEVICE_EVENT_TRANSFER, ProtoBufferUtil.toProtoBuffer(taskEventData, TaskEventDataProto.TaskEventData.class).toByteArray());
        log.info("send event to DDS type:{} deviceId:{}", taskEventData.getDeviceType(), taskEventData.getDeviceId());
    }

    private List<RdEventMeterData> saveEventSubData(String seq, CosemData notificationDataValue, DeviceNotificationDto notificationItemList) {
        List<RdEventMeterData> rdEventMeterDataList = new ArrayList<>();
        for (int i = 0; i < notificationItemList.getObjectList().size(); i++) {
            GroupSubDataItem groupSubDataItem = notificationItemList.getObjectList().get(i);
            if (groupSubDataItem.getDataGroupIds().contains(GroupSubDataItem.SpecialDataGroup.TIME_DATE.getCode())
                    || groupSubDataItem.getDataGroupIds().contains(GroupSubDataItem.SpecialDataGroup.EVENT_CODE.getCode())) {
                continue;
            }
            Long subDataItemId = groupSubDataItem.getSubDataItemId();
            CosemData data = notificationDataValue.getChildAt(0).getChildAt(i).getIsNull() ? notificationDataValue.getChildAt(i) : notificationDataValue.getChildAt(0).getChildAt(i);
            Object value = cosemXmlService.getData(data.getType(), data.getValue());

            RdEventMeterData rdEventMeterData = new RdEventMeterData();
            rdEventMeterData.setLogSeq(seq);
            rdEventMeterData.setSubDataItemId(subDataItemId);
            rdEventMeterData.setValue(String.valueOf(value));
            rdEventMeterDataList.add(rdEventMeterData);
//            rdEventMeterDataMapper.insert(rdEventMeterData);
        }
        return rdEventMeterDataList;
    }

    private List<RdEventDcuData> saveDcuEventSubData(String seq, Integer type, CosemData notificationDataValue, DeviceNotificationDto notificationItemList) {
        int index = 0;
        List<RdEventDcuData> rdEventDcuDataList = new ArrayList<>();
        for (GroupSubDataItem groupSubDataItem : notificationItemList.getObjectList()) {
            if (groupSubDataItem.getDataGroupIds().contains(GroupSubDataItem.SpecialDataGroup.TIME_DATE.getCode())
                    || groupSubDataItem.getDataGroupIds().contains(GroupSubDataItem.SpecialDataGroup.EVENT_CODE.getCode())) {
                index++;
                continue;
            }

            Long subDataItemId = groupSubDataItem.getSubDataItemId();
            CosemData data = notificationDataValue.getChildAt(0).getChildAt(index++);
            Object value = cosemXmlService.getData(data.getType(), data.getValue());
            if (needAsciiDecodeEventTypes.contains(type)) {
                value = new String(ByteUtils.hexStringToByte(Convert.toStr(value)), Charset.forName("utf-8"));
            }
            RdEventDcuData rdEventDcuData = new RdEventDcuData();
            rdEventDcuData.setLogSeq(seq);
            rdEventDcuData.setSubDataItemId(subDataItemId);
            rdEventDcuData.setValue(String.valueOf(value));
            rdEventDcuDataList.add(rdEventDcuData);
            // rdEventDcuDataMapper.insert(rdEventDcuData);
        }
        return rdEventDcuDataList;
    }

    private Long getEventTv(Date uploadDate, CosemData notificationDataValue, DeviceNotificationDto notificationItemList, Long dataItemId) {
        int index = 0;
        if (notificationItemList == null) {
            return uploadDate.getTime() / 1000;
        }
        for (GroupSubDataItem groupSubDataItem : notificationItemList.getObjectList()) {
            if (groupSubDataItem.getDataGroupIds().contains(GroupSubDataItem.SpecialDataGroup.TIME_DATE.getCode())) {
                CosemData data;
                if (dataItemId == null) {
                    data = notificationDataValue.getChildAt(0).getChildAt(index);
                } else {
                    data = notificationDataValue.getChildAt(index);
                }
                Object timeObj = cosemXmlService.getData(data.getType(), data.getValue());
                Date eventTv = null;
                if (timeObj instanceof String) {
                    eventTv = CosemUtils.parseOctStringDataTime((String) timeObj);
                } else if (timeObj instanceof Date) {
                    eventTv = (Date) timeObj;
                } else {
                    log.error("fail to transfer date from notification data");
                }
                if (eventTv != null) {
                    return eventTv.getTime() / 1000;
                }
            }
            index++;
        }
        return uploadDate.getTime() / 1000;
    }
}
